package ch.mobi.osgi2maven2.osgi;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.google.code.mjl.Log;
import com.google.code.mjl.LogFactory;

public class OsgiResolver {

	private final List<OsgiBundle> allBundles = new ArrayList<OsgiBundle>();
	private static Log logger = LogFactory.getLog();

	public OsgiResolver(File pluginDirectory) throws IOException {
		for (String jarFile : pluginDirectory.list()) {

			try {
				logger.info("loading plugin %s", jarFile);
				OsgiBundle file = new OsgiBundle(new File(pluginDirectory, jarFile));

				allBundles.add(file);
			} catch (RuntimeException e) {
				logger.warn(e, "could not load %s", jarFile);
			}

		}

	}

	public List<OsgiBundle> transitiveDependencyHull(RequiredBundle... required) {

		LinkedList<RequiredBundle> toDo = new LinkedList<RequiredBundle>();

		for (RequiredBundle requiredBundle : required) {
			toDo.add(requiredBundle);
		}

		LinkedList<OsgiBundle> done = new LinkedList<OsgiBundle>();

		while (toDo.size() > 0) {
			RequiredBundle current = toDo.removeFirst();
			OsgiBundle matchingBundle = findMatchingBundle(current);
			if (!done.contains(matchingBundle)) {
				done.add(matchingBundle);
			}
			addUnresolvedBundlesToToDo(matchingBundle, toDo, done);
		}

		return done;

	}

	private OsgiBundle findMatchingBundle(RequiredBundle required) {
		for (OsgiBundle bundle : allBundles) {
			if (bundle.isRequiredBundle(required)) {
				return bundle;
			}
		}
		throw new RuntimeException(String.format("could not resolve bundle: %s", required));
	}

	private void addUnresolvedBundlesToToDo(OsgiBundle plugin, LinkedList<RequiredBundle> toDo, LinkedList<OsgiBundle> done) {
		for (RequiredBundle required : plugin.getRequiredBundles()) {
			if (!isAlreadyResolved(required, done)) {
				toDo.add(required);
			}
		}
	}

	private boolean isAlreadyResolved(RequiredBundle required, LinkedList<OsgiBundle> done) {
		for (OsgiBundle bundle : done) {
			if (bundle.isRequiredBundle(required)) {
				return true;
			}
		}
		return false;
	}

}
